package top.ltc_cn.springboot_tools.common;

import top.ltc_cn.springboot_tools.enums.LtcResultEnum;

import java.security.SecureRandom;
import java.time.Instant;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

import static top.ltc_cn.springboot_tools.enums.LtcResultEnum.getByCode;

/**
 * @author ltc-cn xiaoyangcc
 */
public class LtcResult<T> {

    public void setCode(Integer code) {
        this.code = Optional.ofNullable(code).orElseThrow(() -> new IllegalArgumentException("Code cannot be null"));
        this.status = codeToEnumMap.getOrDefault(this.code, LtcResultEnum.SERVICE_UNAVAILABLE);
    }

    public void setStatus(LtcResultEnum status) {
        this.status = Optional.ofNullable(status).orElseThrow(() -> new IllegalArgumentException("Status cannot be null"));
        this.code = this.status.getCode();
        this.msg = this.status.getMsg();
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public void setResult(Integer code, String msg, LtcResultEnum status) {
        if (status != null) {
            this.setCode(status.getCode());
            this.setMsg(Optional.ofNullable(msg).orElse(status.getMsg()));
        } else if (code != null) {
            this.setCode(code);
            this.setMsg(Optional.ofNullable(msg).orElse(this.status.getMsg()));
        }
    }

    public String getMsg() {
        return msg;
    }

    public Integer getCode() {
        return code;
    }

    public T getData() {
        return data;
    }

    public Long getT() {
        return t;
    }

    public LtcResultEnum getStatus() {
        return status;
    }

    public String getId() {
        return id;
    }

    /**
     * 返回体
     */
    private Integer code;
    private String msg;
    private T data;
    private Long t; // 时间戳
    private LtcResultEnum status;
    // 方便日志查询的id
    private String id;

    /**
     * 枚举映射
     */
    private static final Map<Integer, LtcResultEnum> codeToEnumMap = new ConcurrentHashMap<>();
    static {
        for (LtcResultEnum value : LtcResultEnum.values()) {
            codeToEnumMap.put(value.getCode(), value);
        }
    }

    /**
     * 构造方法
     */
    public LtcResult() {
        this(LtcResultEnum.ERROR);
    }
    public LtcResult(LtcResultEnum resultEnum) {
        this(resultEnum.getCode(), resultEnum.getMsg(), null);
    }
    public LtcResult(Integer code, String msg, T data) {
        this.code = Optional.ofNullable(code).orElseThrow(() -> new IllegalArgumentException("Code cannot be null"));
        this.status = codeToEnumMap.getOrDefault(this.code, LtcResultEnum.SERVICE_UNAVAILABLE);
        LtcResultEnum resultEnum = codeToEnumMap.getOrDefault(this.code, LtcResultEnum.SERVICE_UNAVAILABLE);
        this.msg = Optional.ofNullable(msg).orElse(resultEnum.getMsg());
        this.data = data;
        this.t = Instant.now().toEpochMilli(); // 时间戳获取
    }

    /**
     * 添加方便日志查询的id
     */
    public LtcResult<T> addId() {
        // 给 data 添加新数据
        this.id = generateRandomId();
        return this;
    }

    /**
     * 添加方便日志查询的id
     * @param id 查询id
     */
    public LtcResult<T> addId(String id) {
        // 给 data 添加新数据
        this.id = id;
        return this;
    }

    /**
     * 添加方便日志查询的id
     * @param id 查询id
     * @param isLog 是否打印日志
     */
    public LtcResult<T> addId(String id, boolean isLog) {
        // 给 data 添加新数据
        this.id = id;
        if (isLog) {
            System.out.println("[result-log] id:" + id);

        }
        return this;
    }

    /**
     * 添加方便日志查询的id
     * @param isLog 是否打印日志
     */
    public LtcResult<T> addId(boolean isLog) {
        // 给 data 添加新数据
        this.id = generateRandomId();
        if (isLog) {
            System.out.println("[result-log] id:" + id);
        }
        return this;
    }

    /**
     * 生成6位随机数
     */
    private static final SecureRandom RANDOM = new SecureRandom();
    private String generateRandomId() {
        // 生成一个6位的随机数
        int code = RANDOM.nextInt(900000) + 100000;
        // 将整数转换为字符串
        return String.valueOf(code);
    }

    /**
     * 重写toString方法
     *
     * @return 返回结果
     */
    @Override
    public String toString() {
        return "LtcResult{" +
                "code=" + code +
                ", timestamp=" + t +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                ", status=" + status +
                '}';
    }



    /**
     * 获取结果
     *
     * @param ltcResult 结果
     * @param <T>       数据类型
     * @return 结果
     */
    public static <T> LtcResult<T> result(LtcResult<?> ltcResult) {
        return new LtcResult<>(ltcResult.getCode(), ltcResult.getMsg(), null);
    }

    public static <T> LtcResult<T> result(Integer code) {
        return new LtcResult<>(code, getByCode(code).getMsg(), null);
    }

    public static <T> LtcResult<T> result(Integer code, String msg) {
        return new LtcResult<>(code, msg, null);
    }

    public static <T> LtcResult<T> result(Integer code, String msg, T data) {
        return new LtcResult<>(code, msg, data);
    }

    public static <T> LtcResult<T> resultAsData(LtcResult<?> ltcResult, T data) {
        return new LtcResult<>(ltcResult.getCode(), ltcResult.getMsg(), data);
    }

    public static <T> LtcResult<T> success(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.SUCCESS.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.SUCCESS.getCode(), msg, data);
    }

    public static <T> LtcResult<T> success(String msg) {
        return new LtcResult<>(LtcResultEnum.SUCCESS.getCode(), msg, null);
    }

    public static <T> LtcResult<T> success() {
        return success(null);
    }

    public static <T> LtcResult<T> error(LtcResultEnum resultEnum) {
        return new LtcResult<>(resultEnum.getCode(), resultEnum.getMsg(), null);
    }

    public static <T> LtcResult<T> error(LtcResultEnum resultEnum, T data) {
        return new LtcResult<>(resultEnum.getCode(), resultEnum.getMsg(), data);
    }

    public static <T> LtcResult<T> error(String msg) {
        return new LtcResult<>(LtcResultEnum.ERROR.getCode(), msg, null);
    }

    public static <T> LtcResult<T> error(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.ERROR.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.ERROR.getCode(), msg, data);
    }

    public static <T> LtcResult<T> error(T data) {
        return new LtcResult<>(LtcResultEnum.ERROR.getCode(), LtcResultEnum.ERROR.getMsg(), data);
    }

    public static <T> LtcResult<T> error() {
        return error(LtcResultEnum.ERROR);
    }

    // 其他具体的错误方法
    public static <T> LtcResult<T> failed() {
        return new LtcResult<>(LtcResultEnum.FAILED.getCode(), LtcResultEnum.FAILED.getMsg(), null);
    }

    public static <T> LtcResult<T> failed(String msg ,T data) {
        if (msg == null) {
            msg = LtcResultEnum.FAILED.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.FAILED.getCode(), msg, data);
    }

    public static <T> LtcResult<T> notFound() {
        return error(LtcResultEnum.NOT_FOUND);
    }

    public static <T> LtcResult<T> notFound(String msg) {
        return new LtcResult<>(LtcResultEnum.NOT_FOUND.getCode(), msg, null);
    }

    public static <T> LtcResult<T> notFound(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.NOT_FOUND.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.NOT_FOUND.getCode(), msg, data);
    }

    public static <T> LtcResult<T> unauthorized() {
        return error(LtcResultEnum.UNAUTHORIZED);
    }

    public static <T> LtcResult<T> unauthorized(String msg) {
        return new LtcResult<>(LtcResultEnum.UNAUTHORIZED.getCode(), msg, null);
    }

    public static <T> LtcResult<T> unauthorized(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.UNAUTHORIZED.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.UNAUTHORIZED.getCode(), msg, data);
    }

    public static <T> LtcResult<T> forbidden() {
        return error(LtcResultEnum.FORBIDDEN);
    }

    public static <T> LtcResult<T> forbidden(String msg) {
        return new LtcResult<>(LtcResultEnum.FORBIDDEN.getCode(), msg, null);
    }

    public static <T> LtcResult<T> forbidden(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.FORBIDDEN.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.FORBIDDEN.getCode(), msg, data);
    }

    public static <T> LtcResult<T> badRequest() {
        return error(LtcResultEnum.BAD_REQUEST);
    }

    public static <T> LtcResult<T> badRequest(String msg) {
        return new LtcResult<>(LtcResultEnum.BAD_REQUEST.getCode(), msg, null);
    }

    public static <T> LtcResult<T> badRequest(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.BAD_REQUEST.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.BAD_REQUEST.getCode(), msg, data);
    }

    public static <T> LtcResult<T> notImplemented() {
        return error(LtcResultEnum.NOT_IMPLEMENTED);
    }

    public static <T> LtcResult<T> notImplemented(String msg) {
        return new LtcResult<>(LtcResultEnum.NOT_IMPLEMENTED.getCode(), msg, null);
    }

    public static <T> LtcResult<T> notImplemented(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.SERVICE_UNAVAILABLE.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.NOT_IMPLEMENTED.getCode(), msg, data);
    }

    public static <T> LtcResult<T> serviceUnavailable() {
        return error(LtcResultEnum.SERVICE_UNAVAILABLE);
    }

    public static <T> LtcResult<T> serviceUnavailable(String msg) {
        return new LtcResult<>(LtcResultEnum.SERVICE_UNAVAILABLE.getCode(), msg, null);
    }

    public static <T> LtcResult<T> serviceUnavailable(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.SERVICE_UNAVAILABLE.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.SERVICE_UNAVAILABLE.getCode(), msg, data);
    }

    public static <T> LtcResult<T> gatewayTimeout() {
        return error(LtcResultEnum.GATEWAY_TIMEOUT);
    }

    public static <T> LtcResult<T> gatewayTimeout(String msg) {
        return new LtcResult<>(LtcResultEnum.GATEWAY_TIMEOUT.getCode(), msg, null);
    }

    public static <T> LtcResult<T> gatewayTimeout(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.GATEWAY_TIMEOUT.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.GATEWAY_TIMEOUT.getCode(), msg, data);
    }

    public static <T> LtcResult<T> internetServerError() {
        return new LtcResult<>(LtcResultEnum.INTERNAL_SERVER_ERROR.getCode(), LtcResultEnum.INTERNAL_SERVER_ERROR.getMsg(), null);
    }

    public static <T> LtcResult<T> internetServerError(String msg) {
        return new LtcResult<>(LtcResultEnum.INTERNAL_SERVER_ERROR.getCode(), msg, null);
    }

    public static <T> LtcResult<T> internetServerError(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.INTERNAL_SERVER_ERROR.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.INTERNAL_SERVER_ERROR.getCode(), msg, data);
    }

    public static <T> LtcResult<T> tencentCloudCaptchaNeed() {
        return new LtcResult<>(LtcResultEnum.TENCENT_CLOUD_CAPTCHA_NEED.getCode(), LtcResultEnum.TENCENT_CLOUD_CAPTCHA_NEED.getMsg(), null);
    }

    public static <T> LtcResult<T> tencentCloudCaptchaNeed(String msg) {
        return new LtcResult<>(LtcResultEnum.TENCENT_CLOUD_CAPTCHA_NEED.getCode(), msg, null);
    }

    public static <T> LtcResult<T> tencentCloudCaptchaNeed(String msg, T data) {
        if (msg == null) {
            msg = LtcResultEnum.TENCENT_CLOUD_CAPTCHA_NEED.getMsg();
        }
        return new LtcResult<>(LtcResultEnum.TENCENT_CLOUD_CAPTCHA_NEED.getCode(), msg, data);
    }
}
